﻿using System;
using System.Collections.Generic;
using System.Threading.Tasks;

using RexToy.ORM;

using Monitor.Core.Sensor;
using Monitor.Core.Entity;

namespace Monitor.Core
{
    public class SensorController
    {
        public List<ISensor> LoadSensors()
        {
            Dictionary<int, ISensor> _dict = new Dictionary<int, ISensor>();
            List<ISensor> sensors = new List<ISensor>();
            using (var session = SessionFactory.OpenSession())
            {
                var all = session.FindBy<SensorDef>();
                var relations = session.FindBy<SensorRelation>();

                foreach (var def in all)
                {
                    _dict[def.Id] = CreateSensor(def);
                }

                foreach (var def in all)
                {
                    if (!this.HasParent(def, relations))
                        sensors.Add(_dict[def.Id]);

                    if (this.HasChild(def, relations))
                    {
                        var s = _dict[def.Id] as ICompositeSensor;
                        var children = this.GetChildIds(def, relations);
                        foreach (var c in children)
                        {
                            s.AddComponent(_dict[c]);
                        }
                    }
                }
            }
            return sensors;
        }

        private ISensor CreateSensor(SensorDef def)
        {
            ISensor s = null;
            switch (def.Type)
            {
                case SensorType.Mongo:
                    s = new MongoSensor(def.Id, new Uri(def.Uri));
                    break;

                case SensorType.MongoReplica:
                    s = new MongoReplicaSensor(def.Id);
                    break;

                case SensorType.MongoConfig:
                    s = new MongoConfigReplicaSensor(def.Id);
                    break;

                case SensorType.MongoShard:
                    s = new MongoShardSensor(def.Id);
                    break;

                case SensorType.Zookeeper:
                    s = new ZookeeperSensor(def.Id, new Uri(def.Uri));
                    break;

                case SensorType.ZookeeperCluster:
                    s = new ZookeeperClusterSensor(def.Id);
                    break;

                case SensorType.StormNimbus:
                    s = new StormNimbusSensor(def.Id, new Uri(def.Uri));
                    break;

                case SensorType.StormSupervisor:
                    s = new StormSupervisorSensor(def.Id);
                    break;

                case SensorType.StormCluster:
                    s = new StormSensor(def.Id);
                    break;

                case SensorType.Kafka:
                    s = new KafkaSensor(def.Id, new Uri(def.Uri));
                    break;

                case SensorType.KafkaCluster:
                    s = new KafkaClusterSensor(def.Id);
                    break;

                case SensorType.Redis:
                    s = new RedisSensor(def.Id, new Uri(def.Uri));
                    break;
            }
            s.Description = def.Description;
            s.Interval = def.Interval;
            return s;
        }

        private bool HasParent(SensorDef def, List<SensorRelation> relations)
        {
            foreach (var r in relations)
            {
                if (def.Id == r.ChildId)
                    return true;
            }
            return false;
        }

        private bool HasChild(SensorDef def, List<SensorRelation> relations)
        {
            foreach (var r in relations)
            {
                if (def.Id == r.ParentId)
                    return true;
            }
            return false;
        }

        private List<int> GetChildIds(SensorDef def, List<SensorRelation> relations)
        {
            List<int> childIds = new List<int>();
            foreach (var r in relations)
            {
                if (r.ParentId == def.Id)
                    childIds.Add(r.ChildId);
            }
            return childIds;
        }
    }
}
